package leafedbox.utils
{
	import flash.utils.describeType;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	
	/**
	 * A utility class for working with objects.
	 */
	public class ObjectUtil
	{
		//----------------------------------------------------------------------
		// Static methods
		//----------------------------------------------------------------------

		/**
		 * Creates an object and assigns its properties from a hash.  This method
		 * can be nested to easily create an object hierarchy.  This methods is
		 * mainly used for quickly creating test data and should not be used
		 * in a production application.
		 *
		 * @param classRef  A reference to the class to instantiate.
		 * @param args      A key/value hash that is applied to the object.
		 *
		 * @return  An object.
		 */
		public static function create(classRef:Class, args:Object):*
		{
			var obj : Object = new classRef();
			
			for(var propName:String in args) {
				if(args[propName] is Array) {
					obj[propName] = args[propName].slice();
				} else {
					obj[propName] = args[propName];
				}
			}
			
			return obj;
		}
		

		/**
		 * Performs a copy of an object.  The depth of the object can be specified 
		 * through the <code>options</code> parameter.
		 */
		public static function clone(src:*, options:Object=null):*
		{
			var dest:*;
			
			if(src is Object) {
				var value:*;
				var classRef : Class = getDefinitionByName(getQualifiedClassName(src)) as Class;
				dest = new classRef();
				
				// Lookup vars and accessors
				var propNames : Array = new Array();
				var xml : XML = describeType(src);
				for each(var variableXml:XML in xml.variable) {
					propNames.push(variableXml.@name);
				}

				for each(var accessorXml:XML in xml.accessor) {
					if(accessorXml.@access == "readwrite") {
						propNames.push(accessorXml.@name);
					}
				}
				
				// Perform copy
				for each(var propName:String in propNames) {
					value = src[propName];
					
					// Copy items if an array, otherwise do a straight copy.
					if(value is Array) {
						dest[propName] = new Array();
						for each(var item:* in value) {
							if(options && options[propName]) {
								dest[propName].push(ObjectUtil.clone(item, options[propName]));
							}
							else {
								dest[propName].push(item);
							}
						}
					}
					else {
						if(options && options[propName]) {
							dest[propName].push(ObjectUtil.clone(value, options[propName]));
						}
						else {
							dest[propName] = value;
						}
					}
				}
			}
			else {
				dest = src;
			}
			
			return dest;
		}
	}
}
